home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
pctchnqs
/
1992
/
number2
/
rtchdw.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-16
|
8KB
|
233 lines
#pragma inline
#pragma option -1 /* generate 286 instructions */
/* RTCHDW.C -- AT Real-Time Clock control functions
* Author Jim Mischel. Last update 03/22/92 */
#include <stdio.h>
#include <dos.h>
#include "rtc.h"
/* Loop until "Update in Progress" bit is clear */
static void WaitForUpdate (void) {
while (ReadCMOS (SRA) & UIP)
;
}
/* Read Value from CMOS RAM */
int ReadCMOS (int Addr) {
int ch;
asm pushf /* save interrupt flag */
disable ();
if (Addr < SRA) WaitForUpdate ();
outportb (CMOS_Control, Addr);
ch = inportb (CMOS_Data);
asm popf /* restore interrupt flag */
return ch;
} /* ReadCMOS */
/* Write Value to CMOS RAM */
void WriteCMOS (int Addr, int Value) {
asm pushf /* save interrupt flag */
disable ();
if (Addr < SRA) WaitForUpdate ();
outportb (CMOS_Control, Addr);
outportb (CMOS_Data, Value);
asm popf /* restore interrupt flag */
} /* WriteCMOS */
/* Compute and store new CMOS checksum */
void NewCMOSChecksum (void) {
int Loc, CheckSum = 0;
for (Loc = 0x10; Loc < 0x2E; Loc++)
CheckSum += ReadCMOS (Loc);
WriteCMOS (0x2E, (CheckSum >> 8));
WriteCMOS (0x2F, (CheckSum & 0xFF));
}
/* ISR pointers initially point to DummyIsr in case an
* interrupt is enabled for which no ISR has been installed. */
static void far DummyIsr (void) {
}
static void far (*PeriodicIsr) (void) = DummyIsr;
static void far (*UpdateIsr) (void) = DummyIsr;
static void far (*AlarmIsr) (void) = DummyIsr;
/* Setup periodic interrupt frequency and ISR */
int SetPeriodicInt (int Freq, void far (*isr)()) {
if (ReadCMOS (SRB) & PIE)
return 1; /* can't set -- already enabled */
if (isr != NULL) PeriodicIsr = isr;
/* set new periodic rate */
WriteCMOS (SRA, (ReadCMOS (SRA) & 0xf0) | (Freq & 0x0f));
return 0;
}
/* Setup update-ended ISR */
int SetUpdateInt (void far (*isr)()) {
if (ReadCMOS (SRB) & UIE)
return 1; /* can't set -- already enabled */
if (isr != NULL) UpdateIsr = isr;
return 0;
}
/* Convert binary value (0-99) to BCD */
static int BinToBCD (int Bin) {
return ((Bin / 10) << 4) + (Bin % 10);
}
/* Setup alarm time and ISR */
int SetAlarmInt (struct RTCTIME *Time, void far (*isr)()) {
unsigned char srb;
if (ReadCMOS (SRB) & AIE)
return 1; /* already set, exit with error */
if (isr != NULL) AlarmIsr = isr;
srb = ReadCMOS (SRB);
WriteCMOS (SRB, srb | 0x80); /* turn on SET bit */
WriteCMOS (0x05, (Time->Hour < 0xc0) ?
BinToBCD (Time->Hour) : Time->Hour);
WriteCMOS (0x03, (Time->Min < 0xc0) ?
BinToBCD (Time->Min) : Time->Min);
WriteCMOS (0x01, (Time->Sec < 0xc0) ?
BinToBCD (Time->Sec) : Time->Sec);
WriteCMOS (SRB, srb); /* restore SET bit */
return 0;
}
/* Enable individual RTC interrupts */
void EnableRTCint (int Which) {
WriteCMOS (SRB, (ReadCMOS (SRB) |
(Which & (UF | PF | AF))));
}
/* Disable individual RTC interrupts */
void DisableRTCint (int Which) {
WriteCMOS (SRB, (ReadCMOS (SRB) &
~(Which & (UF | PF | AF))));
}
/* Reset individual RTC interrupts and ISRs */
void ResetRTCint (int Which) {
DisableRTCint (Which);
if (Which & PIE) {
PeriodicIsr = DummyIsr;
/* reset rate to 1024 ticks/sec */
WriteCMOS (SRA, (ReadCMOS (SRA) & 0xf0) | 6);
}
if (Which & UIE) UpdateIsr = DummyIsr;
if (Which & AIE) AlarmIsr = DummyIsr;
}
static void far NewRTCint (void); /* ISR Prototype */
static void interrupt (*OldRTCint) () = NULL; /* Old RTC ISR */
/* Pointer to new RTC ISR */
static void interrupt (*RTCintPtr) () =
(void interrupt *)NewRTCint;
/* Enable the RTC interrupt */
void TimerOn (void) {
disable ();
if (OldRTCint == NULL) { /* save old RTC int vector */
OldRTCint = getvect (RTCINT);
setvect (RTCINT, RTCintPtr);
}
ReadCMOS (SRC); /* clear pending RTC interrupts... */
/* ...and enable RTC interrupt */
outportb (PIC2ctrl, inportb (PIC2ctrl) & 0xfe);
enable ();
}
/* Disable RTC hardware interrupt */
void TimerOff (void) {
disable ();
/* disable RTC interrupt */
outportb (PIC2ctrl, inportb (PIC2ctrl) | 1);
setvect (RTCINT, OldRTCint); /* reset RTC ISR */
OldRTCint = NULL;
enable ();
}
/* New INT 70H ISR. Because the state of the stack is unknown
* when this function is entered, we must create a new stack
* before doing any processing. As a result there can be no
* automatic (i.e. stack) variables defined within this function. */
/* Define stack size and number of stacks */
#define StackSize 128
#define Stacks 3
#define SaveRecordSize 8
static char NewStack[StackSize*Stacks];
static unsigned char IntFlags;
static void far NewRTCint (void) {
/* save caller's context and setup new stack */
asm xchg bp,[word ptr cs:SaveArea] /* get next stack area */
asm cmp bp,Offset EndSaveArea /* last stack? */
asm jc Around /* nope, OK */
asm jmp StackError /* Stack overflow! */
Around:
asm mov [word ptr cs:bp+2],sp /* save stack */
asm mov [word ptr cs:bp+4],ss
asm mov sp,[word ptr cs:SaveArea] /* get and save... */
asm mov [word ptr cs:bp+6],sp /* ...original BP */
asm mov sp,[word ptr cs:bp] /* Setup new SP... */
asm add bp,SaveRecordSize /* ...and point to... */
asm mov [word ptr cs:SaveArea],bp /* ...next save area */
asm mov bp,DGROUP
asm mov ss,bp /* SS = local data segment */
asm pusha /* save general registers... */
asm push es /* ...and segment registers... */
asm push ds /* ...on new stack */
asm mov ds,bp /* ds = ss */
/* Determine which interrupts occurred */
IntFlags = ReadCMOS (SRC) & ReadCMOS (SRB);
enable (); /* interrupts OK now */
/* call appropriate interrupt routines */
if (IntFlags & PF) (*PeriodicIsr) ();
if (IntFlags & UF) (*UpdateIsr) ();
if (IntFlags & AF) (*AlarmIsr) ();
outportb (PIC2data, EOI); /* Reset interrupt controllers */
outportb (PIC1data, EOI);
/* restore caller's context and return */
disable ();
asm pop ds /* restore segment registers... */
asm pop es
asm popa /* ...and general registers */
asm mov bp,[word ptr cs:SaveArea] /* Restore... */
asm sub bp,SaveRecordSize /* ...save area pointer, */
asm mov [word ptr cs:SaveArea],bp
asm mov ss,[word ptr cs:bp+4] /* ...stack,... */
asm mov sp,[word ptr cs:bp+2]
asm pop bp /* ...and BP */
asm iret
/*
* Stack overflow handler.
* Display an error message and hang the system.
*/
StackError:
asm mov ax,cs
asm mov ds,ax
asm mov dx,offset OverflowMessage
asm mov ah,9
asm int 21h
DeadLoop: /* system hangs here */
asm jmp short DeadLoop
/*** Local data ***/
asm OverflowMessage = $
asm db 13,10,7,'RTC Stack overflow'
asm db 13,10,'System Halted$'
asm SaveArea = $
asm dw Offset SaveArea+2
asm dw Offset DGROUP:NewStack + (Stacks * StackSize)
asm dw 3 dup (?)
asm dw Offset DGROUP:NewStack + ((Stacks-1) * StackSize)
asm dw 3 dup (?)
asm dw Offset DGROUP:NewStack + ((Stacks-2) * StackSize)
asm dw 3 dup (?)
asm EndSaveArea = $
}